iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
IT Operation

系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server系列 第 10

Day 10|從單台走向多台:PowerShell Remoting 批次巡檢 Windows Server

  • 分享至 

  • xImage
  •  

前面幾天,我們已經把單台 Windows Server 的巡檢內容慢慢補齊。

目前可以檢查:

CPU
Memory
Disk
Service
Uptime
Event Log

如果今天只有一台 Server,其實已經很好用了。

但真正的企業環境,很少只有:

SERVER01

更常見的是:

SERVER01
SERVER02
SERVER03
SERVER04
SERVER05
...

甚至幾十台、幾百台。

這時如果我們還是:

RDP SERVER01

執行 PowerShell

RDP SERVER02

再執行一次

RDP SERVER03

再執行一次

那其實只是把原本的人工巡檢,換成「人工執行 Script」。

還不能算真正的自動化。

所以 Day 10 要處理一個很重要的問題:

能不能在一台管理電腦上,直接取得其他 Windows Server 的資料?

答案就是:

PowerShell Remoting

今天主要會碰到:

Test-WSMan
Invoke-Command
New-PSSession
Get-PSSession
Remove-PSSession

最終我們希望做到:

Management Server

├── SERVER01
├── SERVER02
├── SERVER03
└── SERVER04

PowerShell Remoting

收集巡檢資料

統一報表
PowerShell Remoting 是什麼?

可以先把它理解成:

從目前這台電腦,遠端執行另一台 Windows 電腦上的 PowerShell 指令。

例如平常我們在 SERVER01 上執行:

Get-Service

只能取得 SERVER01 的 Service。

如果使用 PowerShell Remoting:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {
Get-Service
}

就可以從管理端直接要求:

SERVER01,請幫我執行 Get-Service,再把結果傳回來。

這樣就不需要先 RDP 進 Server。

PowerShell Remoting 背後是什麼?

Windows PowerShell Remoting 常見會透過:

WinRM
Windows Remote Management

處理遠端管理。

概念大概是:

PowerShell

WinRM

Network

Remote Windows Server

執行 Command

回傳 Object

常見 WinRM Port:

HTTP 5985
HTTPS 5986

這裡要注意:

5985 使用 HTTP,不代表驗證資訊就一定是明文直接在網路上傳送。

在網域環境中,PowerShell Remoting 通常會搭配 Kerberos 等 Windows 驗證機制。

今天先專注在操作,不深入 WinRM 驗證架構。

第一件事:確認 WinRM 能不能連

PowerShell 提供:

Test-WSMan

例如:

Test-WSMan SERVER01

如果正常,可能看到類似:

wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0

代表:

SERVER01 的 WinRM 可以回應。

如果無法連線,可能會看到:

WinRM cannot complete the operation...

這時候就要開始排查。

PowerShell Remoting 不通時,先不要一直改設定

我會先按照順序確認:

① DNS
② Network
③ Port
④ WinRM Service
⑤ Firewall
⑥ Authentication
⑦ Permission

例如先:

Resolve-DnsName SERVER01

確認 DNS。

再:

Test-Connection SERVER01 -Count 1

接著確認 WinRM Port:

Test-NetConnection -ComputerName SERVER01
-Port 5985

可能看到:

ComputerName : SERVER01
RemotePort : 5985
TcpTestSucceeded : True

這樣排查會比一開始就亂改 Firewall 或 TrustedHosts 安全很多。

Remote Server 必須支援 Remoting

如果是在允許進行遠端管理的測試或管理環境,可在目標 Windows 主機上以系統管理員權限確認 PowerShell Remoting 設定。

常見指令是:

Enable-PSRemoting

它會協助設定:

WinRM Service
Listener
Firewall Rule
PowerShell Remoting

在很多 Windows Server 環境裡,WinRM 可能已經由系統設定或 Group Policy 管理。

所以企業環境裡不要看到不通就直接:

Enable-PSRemoting -Force

最好先確認:

這台 Server 的 WinRM 是不是由公司的 GPO 或資安政策統一管理?

這也是維運上很重要的習慣。

第一個 Invoke-Command

假設:

Test-WSMan SERVER01

正常。

就可以試:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {
hostname
}

可能回:

SERVER01

這表示我們已經成功做到:

從本機讓 SERVER01 執行指令。

ScriptBlock 是什麼?

這裡第一次看到:

-ScriptBlock {
...
}

可以先把它理解成:

我要交給遠端 Server 執行的 PowerShell 程式。

例如:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-Service

}

這裡:

Get-Service

不是在本機執行。

而是在:

SERVER01

執行。

這個觀念非常重要。

確認到底在哪一台機器執行

可以做個簡單測試:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    $env:COMPUTERNAME

}

結果:

SERVER01

如果本機叫:

ADMIN-PC

但結果是:

SERVER01

就可以確認 ScriptBlock 的內容確實是在 Remote Server 執行。

取得遠端 Service

例如:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-Service W32Time

}

可能得到:

Status Name DisplayName PSComputerName


Running W32Time Windows Time SERVER01

這裡可能會多看到一個很重要的欄位:

PSComputerName

PowerShell Remoting 會幫我們保留:

這筆資料到底來自哪台電腦。

這對批次巡檢非常有用。

那 CPU、Memory 也可以嗎?

當然可以。

例如 CPU:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-CimInstance Win32_Processor |
    Select-Object Name, LoadPercentage

}

Memory:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-CimInstance Win32_OperatingSystem |
    Select-Object `
        TotalVisibleMemorySize,
        FreePhysicalMemory

}

Disk:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-CimInstance Win32_LogicalDisk `
        -Filter "DriveType=3"

}

有沒有發現?

Day 7、Day 8 學的東西幾乎不用重學。

只是從:

Local

變成:

Remote
真正有趣的是:ComputerName 可以放很多台

假設現在有:

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

可以直接:

Invoke-Command -ComputerName $Servers
-ScriptBlock {

    $env:COMPUTERNAME

}

可能得到:

SERVER01
SERVER02
SERVER03

也就是說:

Invoke-Command 本身就可以對多台電腦執行。

這才是 Day 10 真正重要的地方。

一次取得多台 Server 的 Uptime

例如:

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

Invoke-Command -ComputerName $Servers
-ScriptBlock {

    $OS = Get-CimInstance Win32_OperatingSystem

    $Uptime = (Get-Date) - $OS.LastBootUpTime

    [PSCustomObject]@{

        ComputerName = $env:COMPUTERNAME

        LastBootTime = $OS.LastBootUpTime

        UptimeDays = [math]::Round(
            $Uptime.TotalDays,
            1
        )

    }

}

結果可能:

ComputerName LastBootTime UptimeDays


SERVER01 2026/09/05 03:12 13.1
SERVER02 2026/08/20 01:35 29.2
SERVER03 2026/09/17 02:10 1.2

以前需要 RDP 三台。

現在一條流程就處理完了。

開始把 CPU、Memory、Uptime 放在一起

我們來做第一個遠端 Health Check。

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

$Results = Invoke-Command -ComputerName $Servers
-ScriptBlock {

    # CPU
    $CPUUsage = [math]::Round(
        (
            Get-CimInstance Win32_Processor |
            Measure-Object `
                -Property LoadPercentage `
                -Average
        ).Average,
        2
    )


    # Memory
    $OS = Get-CimInstance Win32_OperatingSystem

    $TotalMemory = $OS.TotalVisibleMemorySize

    $FreeMemory = $OS.FreePhysicalMemory

    $MemoryUsage = [math]::Round(
        (
            ($TotalMemory - $FreeMemory) /
            $TotalMemory
        ) * 100,
        2
    )


    # Uptime
    $Uptime = (Get-Date) - $OS.LastBootUpTime


    # Output
    [PSCustomObject]@{

        ComputerName = $env:COMPUTERNAME

        CPUUsage     = $CPUUsage

        MemoryUsage  = $MemoryUsage

        UptimeDays   = [math]::Round(
            $Uptime.TotalDays,
            1
        )

        CheckTime    = Get-Date

    }

}

最後:

$Results

可能看到:

ComputerName CPUUsage MemoryUsage UptimeDays


SERVER01 18 62.3 13.1
SERVER02 43 78.1 29.2
SERVER03 10 51.7 1.2

這就是第一個:

Multi-Server Health Check

這時候其實已經跨了一大步

Day 7 的架構是:

SERVER01

PowerShell

Health Check

Day 10 已經變成:

          ADMIN-PC
             │
    PowerShell Remoting
             │
   ┌─────────┼─────────┐
   │         │         │
   ▼         ▼         ▼

SERVER01 SERVER02 SERVER03
│ │ │
└─────────┼─────────┘

Results

CSV Report

這開始比較像真正的企業維運工具。

把結果輸出 CSV

前面已經很熟了:

$ReportFolder = "C:\Temp"

if (-not (Test-Path $ReportFolder)) {

New-Item `
    -Path $ReportFolder `
    -ItemType Directory |
    Out-Null

}

$Date = Get-Date -Format "yyyyMMdd"

接著:

$Results |
Select-Object ComputerName, CPUUsage, MemoryUsage, UptimeDays, CheckTime | Export-Csv
-Path "$ReportFolder\Server_Health_$Date.csv" -NoTypeInformation
-Encoding UTF8

最後:

C:\Temp\Server_Health_20260918.csv

例如:

ComputerName CPUUsage MemoryUsage UptimeDays
SERVER01 18 62.3 13.1
SERVER02 43 78.1 29.2
SERVER03 10 51.7 1.2

現在工程師只需要打開一份報表。

而不是登入三台 Server。

但如果其中一台 Server 連不上呢?

這就是實際環境一定會碰到的問題。

假設:

SERVER01 → OK
SERVER02 → WinRM 不通
SERVER03 → OK

我們不希望:

SERVER02 出錯

整批巡檢亂掉

Day 6 學的:

try
catch

現在又派上用場了。

我比較喜歡先逐台確認

雖然:

Invoke-Command -ComputerName $Servers

可以一次處理多台,

但寫第一版維運工具時,我反而會使用:

foreach

因為比較容易清楚記錄:

哪台成功
哪台失敗
失敗原因

例如:

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

$Results = @()

foreach ($Server in $Servers) {

try {

    Test-WSMan `
        -ComputerName $Server `
        -ErrorAction Stop |
        Out-Null

    $Result = Invoke-Command `
        -ComputerName $Server `
        -ErrorAction Stop `
        -ScriptBlock {

            $OS = Get-CimInstance Win32_OperatingSystem

            $CPUUsage = [math]::Round(
                (
                    Get-CimInstance Win32_Processor |
                    Measure-Object `
                        -Property LoadPercentage `
                        -Average
                ).Average,
                2
            )

            $MemoryUsage = [math]::Round(
                (
                    (
                        $OS.TotalVisibleMemorySize -
                        $OS.FreePhysicalMemory
                    ) /
                    $OS.TotalVisibleMemorySize
                ) * 100,
                2
            )

            $Uptime = (Get-Date) - $OS.LastBootUpTime


            [PSCustomObject]@{

                ComputerName = $env:COMPUTERNAME

                Connection   = "Success"

                CPUUsage     = $CPUUsage

                MemoryUsage  = $MemoryUsage

                UptimeDays   = [math]::Round(
                    $Uptime.TotalDays,
                    1
                )

                ErrorMessage = ""

                CheckTime = Get-Date

            }

        }

    $Results += $Result

}
catch {

    $Results += [PSCustomObject]@{

        ComputerName = $Server

        Connection   = "Failed"

        CPUUsage     = $null

        MemoryUsage  = $null

        UptimeDays   = $null

        ErrorMessage = $_.Exception.Message

        CheckTime    = Get-Date

    }

}

}

這樣 SERVER02 就算出問題:

SERVER01 Success
SERVER02 Failed
SERVER03 Success

SERVER03 還是可以繼續執行。

報表現在會更有意義

可能變成:

Server Connection CPU Memory Uptime Error
SERVER01 Success 18% 62% 13d
SERVER02 Failed WinRM connection failed
SERVER03 Success 10% 52% 1d

這時候看到:

SERVER02 = Failed

就知道要處理的是:

Remote Management / Connection

而不是誤判:

SERVER02 CPU、Memory 都沒有資料,所以 Server 壞了。

這種狀態分類很重要。

Ping 跟 WinRM 要分開

可以 Ping:

True

並不代表:

WinRM 可以用

例如:

SERVER01

Ping → OK
Port 5985 → Failed

那問題比較可能落在:

WinRM
Firewall
GPO
Listener
Authentication

反過來:

Ping → Failed

也不能百分之百直接說 Server Down。

因為可能單純:

ICMP 被 Firewall 擋掉

所以到了 Day 10,我們可以把 Connectivity 再細分:

DNS
ICMP
WinRM

而不是只有一個:

Online / Offline
用 Test-NetConnection 檢查 WinRM Port

如果:

Test-WSMan SERVER01

失敗,可以再:

Test-NetConnection -ComputerName SERVER01
-Port 5985

例如:

TcpTestSucceeded : False

這時可以往:

Firewall
WinRM Listener
Network ACL
Service

方向找。

如果:

TcpTestSucceeded : True

但:

Test-WSMan

還是不行,

則可能比較偏:

Authentication
Permission
WinRM Configuration

這就是系統工程師很重要的一個思考方式:

不要只知道「連不上」,要繼續把問題縮小。

網域環境會比較單純

如果:

ADMIN-PC
SERVER01
SERVER02

全部都:

同一個 Active Directory Domain

而且使用者本身有適當的管理權限,

PowerShell Remoting 通常會比較容易處理。

例如:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {
hostname
}

Windows 可以透過網域驗證機制處理身分認證。

非 Domain 環境會比較麻煩

如果是:

Workgroup

或者:

不同 Domain
沒有 Trust

Remoting 設定會複雜一些。

網路上常常會看到:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*"

但我不建議一開始就照抄 *。

因為:

TrustedHosts = *

等於把信任範圍放得非常大。

比較合理的方式是:

先確認環境

確認為什麼不能用 Kerberos

限制 TrustedHosts 範圍

再決定驗證方式

企業環境則應該優先遵循既有的 WinRM / GPO / 資安政策。

New-PSSession 又是什麼?

目前我們一直使用:

Invoke-Command

這種方式很適合:

執行一次工作 → 拿結果 → 結束。

例如:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {
Get-Service
}

但有時候我們會對同一台 Server 做很多操作。

這時候可以建立:

New-PSSession

例如:

$Session = New-PSSession `
-ComputerName SERVER01

確認:

Get-PSSession

可能看到:

Id Name ComputerName State Availability


1 WinRM1 SERVER01 Open Available
使用現有 Session

例如:

Invoke-Command -Session $Session
-ScriptBlock {
Get-Service
}

再:

Invoke-Command -Session $Session
-ScriptBlock {
Get-Process
}

這兩次都使用同一個:

PSSession
用完 Session 要記得清掉

可以:

Remove-PSSession $Session

這就跟 Day 6 提到的:

建立 Connection

工作

工作完成

關閉 Connection

很像。

如果是正式 Script,也很適合搭配:

try
catch
finally

例如:

$Session = $null

try {

$Session = New-PSSession `
    -ComputerName SERVER01 `
    -ErrorAction Stop

Invoke-Command `
    -Session $Session `
    -ScriptBlock {
        hostname
    }

}
catch {

Write-Host $_.Exception.Message

}
finally {

if ($null -ne $Session) {

    Remove-PSSession $Session

}

}

這就是 finally 真正很適合出現的情境之一。

Invoke-Command 還是 PSSession?

可以先簡單這樣分。

情境 建議
執行一次指令 Invoke-Command
對很多台 Server 做一次巡檢 Invoke-Command
需要對同一 Server 做很多連續操作 PSSession
需要保留遠端 Session 狀態 PSSession

目前我們做的是:

每日批次巡檢。

所以我會先以:

Invoke-Command

為主。

不用一開始把事情做得太複雜。

Remote Object 有一點需要知道

假設:

$Result = Invoke-Command -ComputerName SERVER01
-ScriptBlock {
Get-Service W32Time
}

拿回本機之後,這個 Object 並不完全等同:

Get-Service W32Time

直接在本機取得的物件。

Remoting 通常會把物件序列化之後傳回來。

所以你可能會看到:

Deserialized.System.ServiceProcess.ServiceController

這代表:

資料傳回來了,但它不一定還保留原本所有可以直接操作的方法。

例如遠端拿回來的 Service Object,不要想成拿回本機之後再:

$Result.Stop()

就能直接控制遠端 Service。

比較好的思考方式是:

需要在 Remote Server 上執行的動作

放在 ScriptBlock 裡做

需要帶回來分析的資料

回傳 Object

這個差別之後會很重要。

多台巡檢時,我建議回傳乾淨的 PSCustomObject

例如不要直接:

Get-CimInstance Win32_OperatingSystem

把一大堆 Property 全部傳回來。

而是在 Remote Server 上先整理:

[PSCustomObject]@{

ComputerName = $env:COMPUTERNAME

CPU = $CPUUsage

Memory = $MemoryUsage

Uptime = $Uptime.TotalDays

}

再傳回管理端。

也就是:

Remote Server

取得原始資料

計算

整理

只傳需要的結果

Management Server

這樣:

網路傳輸比較少
報表比較乾淨
Script 比較容易維護
今天完整範例:Multi-Server Health Check

把前面的東西整理成一版:

============================================

Multi Server Health Check

PowerShell Remoting

============================================

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

$ReportFolder = "C:\Temp"
$Date = Get-Date -Format "yyyyMMdd"

$ReportFile = "$ReportFolder\Multi_Server_Health_$Date.csv"

============================================

Create Report Folder

============================================

if (-not (Test-Path $ReportFolder)) {

New-Item `
    -Path $ReportFolder `
    -ItemType Directory |
    Out-Null

}

============================================

Results

============================================

$Results = @()

foreach ($Server in $Servers) {

Write-Host "Checking $Server..."


try {

    # Check WinRM
    Test-WSMan `
        -ComputerName $Server `
        -ErrorAction Stop |
        Out-Null


    # Remote Health Check
    $RemoteResult = Invoke-Command `
        -ComputerName $Server `
        -ErrorAction Stop `
        -ScriptBlock {

            # CPU
            $CPUUsage = [math]::Round(
                (
                    Get-CimInstance Win32_Processor |
                    Measure-Object `
                        -Property LoadPercentage `
                        -Average
                ).Average,
                2
            )


            # OS / Memory
            $OS = Get-CimInstance Win32_OperatingSystem


            $MemoryUsage = [math]::Round(
                (
                    (
                        $OS.TotalVisibleMemorySize -
                        $OS.FreePhysicalMemory
                    ) /
                    $OS.TotalVisibleMemorySize
                ) * 100,
                2
            )


            # Uptime
            $Uptime = (Get-Date) - $OS.LastBootUpTime


            # CPU Status
            if ($CPUUsage -ge 90) {

                $CPUStatus = "Critical"

            }
            elseif ($CPUUsage -ge 80) {

                $CPUStatus = "Warning"

            }
            else {

                $CPUStatus = "Normal"

            }


            # Memory Status
            if ($MemoryUsage -ge 90) {

                $MemoryStatus = "Critical"

            }
            elseif ($MemoryUsage -ge 80) {

                $MemoryStatus = "Warning"

            }
            else {

                $MemoryStatus = "Normal"

            }


            # Result
            [PSCustomObject]@{

                ComputerName = $env:COMPUTERNAME

                Connection   = "Success"

                CPUUsage     = $CPUUsage

                CPUStatus    = $CPUStatus

                MemoryUsage  = $MemoryUsage

                MemoryStatus = $MemoryStatus

                LastBootTime = $OS.LastBootUpTime

                UptimeDays   = [math]::Round(
                    $Uptime.TotalDays,
                    1
                )

                ErrorMessage = ""

                CheckTime    = Get-Date

            }

        }


    $Results += $RemoteResult

}
catch {

    $Results += [PSCustomObject]@{

        ComputerName = $Server

        Connection   = "Failed"

        CPUUsage     = $null

        CPUStatus    = "Unknown"

        MemoryUsage  = $null

        MemoryStatus = "Unknown"

        LastBootTime = $null

        UptimeDays   = $null

        ErrorMessage = $_.Exception.Message

        CheckTime    = Get-Date

    }

}

}

============================================

Display

============================================

$Results |
Select-Object `
ComputerName,
Connection,
CPUUsage,
CPUStatus,
MemoryUsage,
MemoryStatus,
UptimeDays

============================================

Export

============================================

$Results |
Select-Object ComputerName, Connection, CPUUsage, CPUStatus, MemoryUsage, MemoryStatus, LastBootTime, UptimeDays, ErrorMessage, CheckTime | Export-Csv
-Path $ReportFile -NoTypeInformation
-Encoding UTF8

Write-Host ""
Write-Host "Health Check Completed"
Write-Host "Report: $ReportFile"
執行結果可能是
ComputerName Connection CPUUsage CPUStatus MemoryUsage MemoryStatus UptimeDays


SERVER01 Success 20 Normal 62.5 Normal 13.1
SERVER02 Failed Unknown
SERVER03 Success 85 Warning 73.2 Normal 5.8

第一眼就可以看到:

SERVER02
→ Connection Failed

以及:

SERVER03
→ CPU Warning

工程師就不用從三台 Server 的完整資料開始翻。

真正環境還有權限問題

Remoting 很常遇到:

Access is denied

這時候不是:

Server Down

而可能單純是:

目前登入的帳號沒有足夠權限。

這也是為什麼我會把:

Connection

和:

Server Health

分開。

例如:

SERVER01
Connection = Success
Health = Warning

以及:

SERVER02
Connection = Failed
Health = Unknown

Unknown 比亂猜成:

Critical

合理很多。

因為:

沒有取得資料,就應該承認目前不知道狀態。

這其實也是做監控與自動化很重要的觀念。

不要把系統管理帳密直接寫進 Script

有時候可能會看到:

$username = "Administrator"
$password = "MyPassword123"

再把帳密直接放進 Script。

這不建議。

因為:

.ps1

本質上就是可以直接開啟閱讀的文字檔。

如果日後要處理:

Credential
Secret
Service Account

應該使用更適合的 Credential / Secret 管理方式,並遵循公司的帳號與權限政策。

這個系列後面如果需要再獨立處理。

現在先不要為了方便,把管理員密碼寫進 .ps1。

最小權限也是重點

也不要因為 PowerShell Remoting 需要權限,就直接認為:

所有人都給 Domain Admin 最簡單。

企業環境應該考慮:

誰可以遠端管理?
可以管理哪些 Server?
允許執行哪些工作?
帳號是否有 Log?
權限是否可以再縮小?

我們今天的 Lab 可以先把功能做出來。

但真正 Production Environment:

能做到,不代表就應該給最大權限去做。

今天真正跨過的是哪個門檻?

其實今天沒有學很多新的「巡檢項目」。

CPU 還是:

Get-CimInstance Win32_Processor

Memory 還是:

Get-CimInstance Win32_OperatingSystem

前面都學過。

真正改變的是執行架構。

以前:

工程師

登入 SERVER01

執行 Script

現在:

             Engineer
                │
                ▼
          Management Host
                │
      PowerShell Remoting
                │
    ┌───────────┼───────────┐
    ▼           ▼           ▼
 SERVER01    SERVER02    SERVER03
    │           │           │
    └───────────┼───────────┘
                ▼
            Report

也就是從:

單機 Automation

開始走向:

集中式 Automation。

Day 10 小結

今天主要碰到了:

Test-WSMan
Invoke-Command
New-PSSession
Get-PSSession
Remove-PSSession
Test-NetConnection

最核心的還是:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    # Remote Command

}

然後進一步把:

SERVER01
SERVER02
SERVER03

全部納入同一份巡檢流程。

到目前為止,我們的工具已經具備:

多台 Server

Remoting

錯誤處理

CPU
Memory
Uptime

Status

CSV Report

前十天如果用一句話總結,就是:

我們已經從一條 PowerShell 指令,慢慢做成一支可以集中巡檢多台 Windows Server 的工具。

這個階段我反而不建議急著一直加新功能。

接下來應該開始整理程式結構,否則 Script 會越來越長,最後自己也不敢改。

Day 11 預告
Day 11|把 PowerShell Script 拆成 Function:別讓巡檢工具變成 500 行的大檔案

目前程式已經包含:

Connectivity
CPU
Memory
Disk
Service
Uptime
Event Log
Remoting
CSV
Error Handling
Log

如果全部一直往同一個 .ps1 裡面加,最後可能會變成:

HealthCheck.ps1

700 行

然後幾個月後:

「這一段到底誰會用到?」

所以 Day 11 我建議先暫停增加巡檢項目,開始重構。

我們會把原本的程式拆成:

Test-ServerConnection

Get-CPUHealth

Get-MemoryHealth

Get-DiskHealth

Get-ServiceHealth

Get-UptimeInfo

Get-EventHealth

Write-Log

最後主程式可能只剩:

讀 Server List

呼叫 Function

收集 Result

產生 Report

Day 11 會是這個 30 天系列第一次從「把功能做出來」開始轉向「把工具寫得可以維護」。


上一篇
Day 9|Windows Event Log 自動巡檢:不要等使用者報錯才去翻事件檢視器
下一篇
Day 11|把 PowerShell Script 拆成 Function:別讓巡檢工具變成 500 行的大檔案
系列文
系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言